﻿using System;
using System.Windows.Forms;

namespace MediaGerbil
{
    /// <summary>
    /// Provides a custom implementation on an editing control that combines the look
    /// and free editing of a TextBox control with the dropdown list with suggestions
    /// of a ComboBox.
    /// </summary>
    public class TitleEditingControl : ComboBox, IDataGridViewEditingControl
    {
        #region .   Private Member Variables   .
        /// <summary>
        /// Text of the editing control before last change. Used to deal with certain editing situations.
        /// </summary>
        private string previousText = string.Empty;
        /// <summary>
        /// True if the value has been changed, otherwise false.
        /// </summary>
        private bool valueChanged = false;
        #endregion

        /// <summary>
        /// Creates a new TitleEditingControl.
        /// </summary>
        public TitleEditingControl()
        {
            // We don't want the combobox to autosize the dropdown list
            IntegralHeight = false;
        }

        /// <summary>
        /// Implements the IDataGridViewEditingControl.EditingControlFormattedValue property.
        /// </summary>
        public object EditingControlFormattedValue
        {
            get
            {
                // In certain situations this.Text will not be set or available yet,
                // so we return the last known contents of the editing control instead.
                try { return this.Text; }
                catch { return previousText; }
            }
            set
            {
                previousText = this.Text;
                this.Text = (string)value;
            }
        }

        /// <summary>
        /// Implements the IDataGridViewEditingControl.GetEditingControlFormattedValue method.
        /// </summary>
        /// <param name="context"></param>
        /// <returns>The current text value of the editing control</returns>
        public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context)
        {
            return EditingControlFormattedValue;
        }

        /// <summary>
        /// Implements the IDataGridViewEditingControl.ApplyCellStyleToEditingControl method.
        /// </summary>
        /// <param name="dataGridViewCellStyle"></param>
        public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
        {
            this.Font = dataGridViewCellStyle.Font;
            this.ForeColor = dataGridViewCellStyle.ForeColor;
            this.BackColor = dataGridViewCellStyle.BackColor;
        }

        /// <summary>
        /// Implements the IDataGridViewEditingControl.EditingControlRowIndex property.
        /// </summary>
        public int EditingControlRowIndex { get; set; }

        /// <summary>
        /// Implements the IDataGridViewEditingControl.EditingControlWantsInputKey method.
        /// </summary>
        /// <param name="key"></param>
        /// <param name="dataGridViewWantsInputKey"></param>
        /// <returns></returns>
        public bool EditingControlWantsInputKey(Keys key, bool dataGridViewWantsInputKey)
        {
            // Let the ComboBox handle the keys listed.
            switch (key & Keys.KeyCode)
            {
                case Keys.Left:
                case Keys.Up:
                case Keys.Down:
                case Keys.Right:
                case Keys.Home:
                case Keys.End:
                case Keys.PageDown:
                case Keys.PageUp:
                    return true;
                default:
                    return !dataGridViewWantsInputKey;
            }
        }

        /// <summary>
        /// Implements the IDataGridViewEditingControl.PrepareEditingControlForEdit method.
        /// </summary>
        /// <param name="selectAll"></param>
        public void PrepareEditingControlForEdit(bool selectAll)
        {
            // Make sure we know what the old text was
            previousText = this.Text;
        }

        /// <summary>
        /// Implements the IDataGridViewEditingControl.RepositionEditingControlOnValueChange property.
        /// </summary>
        public bool RepositionEditingControlOnValueChange
        {
            get { return false; }
        }

        /// <summary>
        /// Implements the IDataGridViewEditingControl.EditingControlDataGridView property.
        /// </summary>
        public DataGridView EditingControlDataGridView { get; set; }

        /// <summary>
        /// Implements the IDataGridViewEditingControl.EditingControlValueChanged property.
        /// </summary>
        public bool EditingControlValueChanged
        {
            get { return valueChanged; }
            set { valueChanged = value; }
        }

        /// <summary>
        /// Implements the IDataGridViewEditingControl.EditingPanelCursor property.
        /// </summary>
        public Cursor EditingPanelCursor
        {
            get { return base.Cursor; }
        }

        /// <summary>
        /// Raises the System.Windows.Forms.Control.Leave event.
        /// </summary>
        /// <param name="e">A System.EventArgs object that contains the event data</param>
        protected override void OnLeave(EventArgs e)
        {
            // Notify the DataGridView that the contents of the cell has changed.
            GerbilLib.MediaItem currentItem = (GerbilLib.MediaItem)EditingControlDataGridView.CurrentRow.DataBoundItem;
            if (currentItem.Title.Trim() != previousText.Trim())
            {
                valueChanged = true;
                this.EditingControlDataGridView.NotifyCurrentCellDirty(true);
            }
            else
            {
                valueChanged = false;
                this.EditingControlDataGridView.NotifyCurrentCellDirty(false);
            }
            base.OnLeave(e);
        }

        protected override void OnTextChanged(EventArgs e)
        {
            this.EditingControlDataGridView.NotifyCurrentCellDirty(true);
            base.OnTextChanged(e);
        }
    }

    /// <summary>
    /// Provides a custom DataGridViewCell class based on the TextBoxCell but
    /// with a custom editing control that combines features from both TextBox
    /// and ComboBox controls.
    /// </summary>
    public class DataGridViewTitleCell : DataGridViewTextBoxCell
    {
        /// <summary>
        /// Creates a new DataGridViewTitleCell object.
        /// </summary>
        public DataGridViewTitleCell()
            : base()
        {
            // Nothing to do here
        }

        /// <summary>
        /// Initializes the control used to edit the cell.
        /// </summary>
        /// <param name="rowIndex">The index of the row being edited.</param>
        /// <param name="initialFormattedValue">The initial value to be displayed in the control</param>
        /// <param name="dataGridViewCellStyle">A cell style that is used to determine the appearance of the hosted control</param>
        public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
        {
            // Set the value of the editing control to the current cell value.
            base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
            TitleEditingControl ctl = DataGridView.EditingControl as TitleEditingControl;
            if (ctl != null) ctl.DropDownStyle = ComboBoxStyle.DropDown;

            if (this.Value == null)
                ctl.Text = (string)this.DefaultNewRowValue;
            else
                ctl.Text = (string)this.Value;
        }

        /// <summary>
        /// Gets the type of the cell's hosted editing control.
        /// </summary>
        public override Type EditType
        {
            // Return the type of the editing control that DataGridViewTitleCell uses.
            get { return typeof(TitleEditingControl); }
        }

        /// <summary>
        /// Gets the type of the value of the cell's hosted editing control.
        /// </summary>
        public override Type ValueType
        {
            // Return the type of the value that DataGridViewTitleCell contains.
            get { return typeof(string); }
        }

        /// <summary>
        /// Gets the default value for the editing control on a new row.
        /// </summary>
        public override object DefaultNewRowValue
        {
            // Use the empty string as the default value.
            get { return string.Empty; }
        }
    }
}
